/*
 * @Date: 2023-03-18 20:58:17
 * @LastEditors: Wangjun
 * @LastEditTime: 2023-05-30 14:43:25
 * @FilePath: \libs\ezip\ezip.go
 * @Description:
 */
package ezip

import (
	"archive/zip"
	"io"
	"os"
	"path/filepath"
	"strings"
)

// 压缩文件
// files 文件数组，可以是不同dir下的文件或者文件夹
// dest 压缩文件存放地址
func Compress(files []*os.File, dest string) error {
	d, _ := os.Create(dest)
	defer d.Close()
	w := zip.NewWriter(d)
	defer w.Close()
	for _, file := range files {
		err := compress(file, "", w)
		if err != nil {
			return err
		}
	}
	return nil
}

func compress(file *os.File, prefix string, zw *zip.Writer) error {
	info, err := file.Stat()
	if err != nil {
		return err
	}
	if info.IsDir() {
		prefix = prefix + "/" + info.Name()
		fileInfos, err := file.Readdir(-1)
		if err != nil {
			return err
		}
		for _, fi := range fileInfos {
			f, err := os.Open(file.Name() + "/" + fi.Name())
			if err != nil {
				return err
			}
			err = compress(f, prefix, zw)
			if err != nil {
				return err
			}
		}
	} else {
		header, err := zip.FileInfoHeader(info)
		header.Name = prefix + "/" + header.Name
		if err != nil {
			return err
		}
		writer, err := zw.CreateHeader(header)
		if err != nil {
			return err
		}
		_, err = io.Copy(writer, file)
		file.Close()
		if err != nil {
			return err
		}
	}
	return nil
}

// 解压
func DecompressReader(readerat io.ReaderAt, size int64, dest string, errprint func(...any), cb func(r io.Reader, fileName string) error) error {
	reader, err := zip.NewReader(readerat, size)
	if err != nil {
		return err
	}
	for _, file := range reader.File {
		filename := dest + file.Name
		if file.FileInfo().IsDir() {
			err = os.MkdirAll(filename, 0755)
			if err != nil {
				errprint(err)
			}
			continue
		}
		dir := filepath.Dir(filename)
		err = os.MkdirAll(dir, 0755)
		if err != nil {
			errprint(err)
			continue
		}
		rc, err := file.Open()
		if err != nil {
			errprint(err)
			continue
		}

		if cb != nil {
			err = cb(rc, filename)
			if err != nil {
				errprint(err)
			}
		} else {
			w, err := os.Create(filename)
			if err != nil {
				rc.Close()
				errprint(err)
				continue
			}
			_, err = io.Copy(w, rc)
			if err != nil {
				rc.Close()
				w.Close()
				errprint(err)
				continue
			}
			w.Close()
		}
		rc.Close()
	}
	return nil
}

// 解压
func Decompress(zipFile, dest string, printError func(...any)) error {
	if !strings.HasSuffix(dest, "/") {
		dest += "/"
	}
	reader, err := zip.OpenReader(zipFile)
	if err != nil {
		return err
	}
	defer reader.Close()
	for _, file := range reader.File {
		filename := dest + file.Name
		if file.FileInfo().IsDir() {
			err = os.MkdirAll(filename, 0755)
			if err != nil {
				if printError != nil {
					printError(err)
				}
			}
			continue
		}
		dir := filepath.Dir(filename)
		err = os.MkdirAll(dir, 0755)
		if err != nil {
			if printError != nil {
				printError(err)
			}
			continue
		}
		rc, err := file.Open()
		if err != nil {
			if printError != nil {
				printError(err)
			}
			continue
		}
		w, err := os.Create(filename)
		if err != nil {
			rc.Close()
			if printError != nil {
				printError(err)
			}
			continue
		}
		_, err = io.Copy(w, rc)
		if err != nil {
			rc.Close()
			w.Close()
			if printError != nil {
				printError(err)
			}
			continue
		}
		w.Close()
		rc.Close()
	}
	return nil
}
